//! 可读写的 (write any read legal) 寄存器
//! 用于保存 trap 向量的配置，包含向量的基地址和向量模式
//!
//! 所有的实现都包含本寄存器，但是其中的值可以是只读的。
//! 如果可写，则允许写入的值由实现来定义。
//!
//! BASE 字段永远是 4-byte 对齐，但是 MODE 字段可以强加更为严格的对齐限制。
//!
//! 当 MODE = Direct 时，所有的 trap 将导致 pc 值被置为 BASE 字段的值。
//!
//! 当 MODE = Vectored 时，所有的同步异常讲导致 pc 被置为 BASE 字段的值，
//! 但是中断则会将 pc 置为 BASE + 4*(interrupt cause num)，
//! 这也是为什么 interrupt cause num 的偶数是保留的。
//!
//! ⚠️ 由于是 WARL 寄存器，所以更改 MODE 之后应当再次读取，
//! 防止平台实现不允许 Direct 或 Vectored
use core::marker::PhantomData;

use bits::{BitsOps, IntoBits};

use crate::{csrr, csrw};

pub fn read() -> usize {
    csrr!(mtvec)
}
pub fn write(reg_val: usize) {
    csrw!(mtvec, reg_val);
}

pub enum Mode {
    Direct,
    Vectored,
    Reserved(usize),
}
impl TryFrom<usize> for Mode {
    type Error = &'static str;

    fn try_from(value: usize) -> Result<Self, Self::Error> {
        Ok(match value {
            0 => Mode::Direct,
            1 => Mode::Vectored,
            2 | 3 => Mode::Reserved(value),
            _ => Err("Out of range: mode must be in 0..=3")?,
        })
    }
}
impl Into<usize> for Mode {
    fn into(self) -> usize {
        match self {
            Mode::Direct => 0,
            Mode::Vectored => 1,
            Mode::Reserved(x) => x,
        }
    }
}
pub struct Cache {
    pub base: usize,
    pub mode: Mode,
    phatom: PhantomData<usize>,
}
impl TryFrom<usize> for Cache {
    type Error = &'static str;
    fn try_from(value: usize) -> Result<Cache, Self::Error> {
        Ok(Cache {
            base: value.bits(2..).read(),
            mode: Mode::try_from(value.bits(0..=1).read())?,
            phatom: PhantomData,
        })
    }
}
impl Into<usize> for Cache {
    fn into(self) -> usize {
        let base = self.base.bits(2..).read();
        let mode = self.mode.into();
        0usize.bits(2..).write(base).bits(0..=1).write(mode)
    }
}
pub fn cache() -> Cache {
    read().try_into().expect("Value from mtvec must be legal")
}
impl Cache {
    pub fn flush(self) {
        write(self.into())
    }
}
